library(tidyverse)
library(nflverse)
library(gt)
nfl_analytics_theme <- function(..., base_size = 12) {
  
  theme(
    text = element_text(family = "Roboto",
                        size = base_size,
                        color = "black"),
    axis.ticks = element_blank(),
    axis.title = element_text(face = "bold"),
    axis.text = element_text(face = "bold"),
    plot.title.position = "plot",
    plot.title = element_markdown(size = 16,
                                  vjust = .02,
                                  hjust = 0.5),
    plot.subtitle = element_markdown(hjust = 0.5),
    plot.caption = element_markdown(size = 8),
    panel.grid.minor = element_blank(),
    panel.grid.major =  element_line(color = "#d0d0d0"),
    panel.background = element_rect(fill = "#f7f7f7"),
    plot.background = element_rect(fill = "#f7f7f7"),
    panel.border = element_blank(),
    legend.background = element_rect(color = "#F7F7F7"),
    legend.key = element_rect(color = "#F7F7F7"),
    legend.title = element_text(face = "bold"),
    legend.title.align = 0.5,
    strip.text = element_text(face = "bold"))
}
teams <- nflreadr::load_teams()

Snap counts

I’d like to replicate that Pickens was used in 59% of snaps against the Cowboys in Week 5.

snap_counts <- load_snap_counts(seasons = most_recent_season())

snap_counts <- snap_counts %>% 
  left_join(x=.,
            y=teams,
            by=c('team' = 'team_abbr'))
snap_counts
── nflverse snap counts ────────────────────────────────────────────────────────────────────────────────────────────────
ℹ Data updated: 2024-10-15 08:40:40 EDT

Roman Wilson

snap_counts %>% 
  filter(player == 'Roman Wilson')
── nflverse snap counts ────────────────────────────────────────────────────────────────────────────────────────────────
ℹ Data updated: 2024-10-15 08:40:40 EDT

Personnel groupings in 2024

(personnel <- nflreadr::load_participation(seasons = 2023, include_pbp = TRUE))
── nflverse play-by-play participation ─────────────────────────────────────────────────────────────────────────────────
ℹ Data updated: 2024-02-28 02:32:38 MST
personnel %>% 
  filter(team == 'PIT')
Error in `filter()`:
ℹ In argument: `team == "PIT"`.
Caused by error:
! object 'team' not found
Backtrace:
 1. personnel %>% filter(team == "PIT")
 3. dplyr:::filter.data.frame(., team == "PIT")
 4. dplyr:::filter_rows(.data, dots, by)
 5. dplyr:::filter_eval(...)
 7. mask$eval_all_filter(dots, env_filter)
 8. dplyr (local) eval()

Analysis of the three-edge look (Watt, Highsmith, Herbig)

From Congelio book

(participation <- nflreadr::load_participation(season = 2024, include_pbp = TRUE))
(participation_split <- participation %>%
  filter(!is.na(offense_formation)) %>%
  filter(posteam == "PIT") %>%
  tidyr::separate_rows(offense_players, sep = ";") %>%
  group_by(offense_personnel, offense_players) %>%
  summarize(total = n(),
            .groups = 'drop'))
roster_2023 <- nflreadr::load_rosters(2023) %>%
  select(full_name, gsis_id, headshot_url)
participation_split <- participation_split %>%
  left_join(roster_2023, by = c("offense_players" = "gsis_id"))
participation_split
LS0tCnRpdGxlOiAiTkZMIEFuYWx5dGljczogRXhwbG9yaW5nIHBlcnNvbm5lbCBncm91cGluZ3MiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIGxpYnJhcmllcywgaW5jbHVkZT1UUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShuZmx2ZXJzZSkKbGlicmFyeShndCkKYGBgCgpgYGB7ciBuZmxfYW5hbHl0aWNzX3RoZW1lLCBpbmNsdWRlPVRSVUV9Cm5mbF9hbmFseXRpY3NfdGhlbWUgPC0gZnVuY3Rpb24oLi4uLCBiYXNlX3NpemUgPSAxMikgewogIAogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiUm9ib3RvIiwKICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGJhc2Vfc2l6ZSwKICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gLjAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjUpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oaGp1c3QgPSAwLjUpLAogICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bihzaXplID0gOCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvciA9ICBlbGVtZW50X2xpbmUoY29sb3IgPSAiI2QwZDBkMCIpLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmN2Y3ZjciKSwKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmN2Y3ZjciKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gIiNGN0Y3RjciKSwKICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiI0Y3RjdGNyIpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC41LAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkKfQpgYGAKCmBgYHtyIHRlYW1zLCBpbmNsdWRlPVRSVUV9CnRlYW1zIDwtIG5mbHJlYWRyOjpsb2FkX3RlYW1zKCkKYGBgCgojIyMgU25hcCBjb3VudHMgCgpJJ2QgbGlrZSB0byByZXBsaWNhdGUgdGhhdCBQaWNrZW5zIHdhcyB1c2VkIGluIDU5JSBvZiBzbmFwcyBhZ2FpbnN0IHRoZSBDb3dib3lzIGluIFdlZWsgNS4KCmBgYHtyIHNuYXBfY291bnRzLCBpbmNsdWRlPVRSVUV9CnNuYXBfY291bnRzIDwtIGxvYWRfc25hcF9jb3VudHMoc2Vhc29ucyA9IG1vc3RfcmVjZW50X3NlYXNvbigpKQoKc25hcF9jb3VudHMgPC0gc25hcF9jb3VudHMgJT4lIAogIGxlZnRfam9pbih4PS4sCiAgICAgICAgICAgIHk9dGVhbXMsCiAgICAgICAgICAgIGJ5PWMoJ3RlYW0nID0gJ3RlYW1fYWJicicpKQpgYGAKCmBgYHtyfQpzbmFwX2NvdW50cyAlPiUgCiAgZmlsdGVyKHBsYXllciA9PSAnR2VvcmdlIFBpY2tlbnMnKSAlPiUgCiAgZ2dwbG90KC4sCiAgICAgICAgIGFlcyh4PXdlZWssCiAgICAgICAgICAgICB5PW9mZmVuc2VfcGN0KSkgKyAKICBnZW9tX2NvbChmaWxsPScjRkZCNjEyJykgKyAKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoMTAwKm9mZmVuc2VfcGN0LCAnJScsIHNlcD0nJykpLCAKICAgICAgICAgICAgY29sb3I9J2JsYWNrJywgZmFtaWx5PSdSb2JvdG8nLCBmb250ZmFjZT0nYm9sZCcsIHNpemU9NSkgKyAKICBnZ3RpdGxlKCcqKkdlb3JnZSBQaWNrZW5zKiogd2Vlay10by13ZWVrIHNuYXAgY291bnRzOiAyMDI0IE5GTCBTZWFzb24nKSArIAogIGxhYnMoeT0nJSBvZiBPZmZlbnNpdmUgU25hcHMgUGxheWVkJywKICAgICAgIHg9J1dlZWsnKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsgCiAgbmZsX2FuYWx5dGljc190aGVtZSgpCmBgYAoKIyMgUm9tYW4gV2lsc29uIAoKYGBge3J9CnNuYXBfY291bnRzICU+JSAKICBmaWx0ZXIocGxheWVyID09ICdSb21hbiBXaWxzb24nKSAlPiUgCiAgZ2dwbG90KC4sCiAgICAgICAgIGFlcyh4PXdlZWssCiAgICAgICAgICAgICB5PW9mZmVuc2Vfc25hcHMpKSArIAogIGdlb21fY29sKGZpbGw9JyNGRkI2MTInKSArIAogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgxMDAqb2ZmZW5zZV9wY3QsICclJywgc2VwPScnKSksIAogICAgICAgICAgICBjb2xvcj0nYmxhY2snLCBmYW1pbHk9J1JvYm90bycsIGZvbnRmYWNlPSdib2xkJywgc2l6ZT01KSArIAogIGdndGl0bGUoJyoqUm9tYW4gV2lsc29uKiogd2Vlay10by13ZWVrIHNuYXAgY291bnRzOiAyMDI0IE5GTCBTZWFzb24nKSArIAogIGxhYnMoeT0nIyBvZiBPZmZlbnNpdmUgU25hcHMgUGxheWVkJywKICAgICAgIHg9J1dlZWsnKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsNykpICsgCiAgIyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIAogIG5mbF9hbmFseXRpY3NfdGhlbWUoKQpgYGAKCgojIFBlcnNvbm5lbCBncm91cGluZ3MgaW4gMjAyNAoKYGBge3IgcGVyc29ubmVsLCBpbmNsdWRlPVRSVUV9CihwZXJzb25uZWwgPC0gbmZscmVhZHI6OmxvYWRfcGFydGljaXBhdGlvbihzZWFzb25zID0gMjAyMywgaW5jbHVkZV9wYnAgPSBUUlVFKSkKYGBgCgpgYGB7cn0KcGVyc29ubmVsICU+JSAKICBmaWx0ZXIodGVhbSA9PSAnUElUJykKYGBgCgoKIyMgQW5hbHlzaXMgb2YgdGhlIHRocmVlLWVkZ2UgbG9vayAoV2F0dCwgSGlnaHNtaXRoLCBIZXJiaWcpIAoKCgoKIyBGcm9tIENvbmdlbGlvIGJvb2sKCmBgYHtyIHBhcnRpY2lwYXRpb24sIGluY2x1ZGU9VFJVRX0KKHBhcnRpY2lwYXRpb24gPC0gbmZscmVhZHI6OmxvYWRfcGFydGljaXBhdGlvbihzZWFzb24gPSAyMDI0LCBpbmNsdWRlX3BicCA9IFRSVUUpKQpgYGAKCgpgYGB7ciBwYXJ0aWNpcGF0aW9uX3NwbGl0LCBpbmNsdWRlPVRSVUV9CihwYXJ0aWNpcGF0aW9uX3NwbGl0IDwtIHBhcnRpY2lwYXRpb24gJT4lCiAgZmlsdGVyKCFpcy5uYShvZmZlbnNlX2Zvcm1hdGlvbikpICU+JQogIGZpbHRlcihwb3N0ZWFtID09ICJQSVQiKSAlPiUKICB0aWR5cjo6c2VwYXJhdGVfcm93cyhvZmZlbnNlX3BsYXllcnMsIHNlcCA9ICI7IikgJT4lCiAgZ3JvdXBfYnkob2ZmZW5zZV9wZXJzb25uZWwsIG9mZmVuc2VfcGxheWVycykgJT4lCiAgc3VtbWFyaXplKHRvdGFsID0gbigpLAogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKSkKYGBgCgpgYGB7ciByb3N0ZXJfMjAyMywgaW5jbHVkZT1UUlVFfQpyb3N0ZXJfMjAyMyA8LSBuZmxyZWFkcjo6bG9hZF9yb3N0ZXJzKDIwMjMpICU+JQogIHNlbGVjdChmdWxsX25hbWUsIGdzaXNfaWQsIGhlYWRzaG90X3VybCkKYGBgCgoKYGBge3J9CnBhcnRpY2lwYXRpb25fc3BsaXQgPC0gcGFydGljaXBhdGlvbl9zcGxpdCAlPiUKICBsZWZ0X2pvaW4ocm9zdGVyXzIwMjMsIGJ5ID0gYygib2ZmZW5zZV9wbGF5ZXJzIiA9ICJnc2lzX2lkIikpCnBhcnRpY2lwYXRpb25fc3BsaXQKYGBg